﻿using VCDIFF;
using VCDIFF.Rebuild;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.IO;

namespace VCDIFF.Tests
{
    
    
    /// <summary>
    ///This is a test class for VCDFileTest and is intended
    ///to contain all VCDFileTest Unit Tests
    ///</summary>
    [TestClass()]
    public class VCDFileTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for WindowsList
        ///</summary>
        [TestMethod()]
        public void WindowsListTest()
        {
            VCDFile target = new VCDFile();
            byte[] windowData = new byte[] {
                // Window
                0x01,       // Win_Indicator
                0x3A,       // Source segment size
                0x00,       // Source segment position
                0x35,       // Length of the delta encoding 
                0x81, 0x0E, // Size of the target window
                0x00,       // Delta_Indicator (no compression)
                0x14,       // Length of data for ADDs and RUNs
                0x18,       // Length of instructions and sizes
                0x03,       // Length of addresses for COPYs
                // Data section for ADDs and RUNs :   \nnot \nIt was a lie !
                0x0A, 0x6E, 0x6F, 0x74, 0x20, 0x0A,
                0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x65, 0x20, 0x21,                
                // Instructions and sizes section
                0x03, 0x3A, 0x00,   // COPY | Size 58 | No mode
                0x02, 0x01, 0x00,   // RUN  | Size 01 | No mode
                0x03, 0x06, 0x00,   // COPY | Size 06 | No mode
                0x01, 0x04, 0x00,   // ADD  | Size 04 | No mode
                0x03, 0x34, 0x00,   // COPY | Size 52 | No mode
                0x02, 0x01, 0x00,   // RUN  | Size 01 | No mode
                0x01, 0x0D, 0x00,   // ADD  | Size 13 | No mode
                0x02, 0x05, 0x00,   // RUN  | Size 05 | No mode
                // Addresses section for COPYs
                0x00, 0x00, 0x06
            };
            RebuildWindows rebuildWindows = new RebuildWindows();
            IList<Window> expected = rebuildWindows.Rebuild(windowData);                                    
            target.WindowsList = expected;
            IList<Window> actual;
            actual = target.WindowsList;

            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for Header
        ///</summary>
        [TestMethod()]
        public void HeaderTest()
        {
            VCDFile target = new VCDFile();
            byte[] headerData = new byte[] {
                // Header
                0xD6,   // V
                0xC3,   // C
                0xC4,   // D
                0x00,   // VCDIFF Version
                0x00,   // Hdr_Indicator : no custom code table, no compression
                0x00,   // Secondary compressor ID
                0x00,   // Length of code table data
                0x00,   // Size of near cache 
                0x00    // Size of same cache
            };
            RebuildHeader rebuildHeader = new RebuildHeader();
            Header expected = rebuildHeader.Rebuild(headerData);
            Header actual;
            target.Header = expected;
            actual = target.Header;

            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for Write
        ///</summary>
        [TestMethod()]
        public void WriteTest()
        {
            VCDFile file = new VCDFile();

            byte[] headerData = new byte[] {
                // Header
                0xD6,   // V
                0xC3,   // C
                0xC4,   // D
                0x00,   // VCDIFF Version
                0x00,   // Hdr_Indicator : no custom code table, no compression
                0x00,   // Secondary compressor ID
                0x00,   // Length of code table data
                0x00,   // Size of near cache 
                0x00    // Size of same cache
            };
            RebuildHeader rebuildHeader = new RebuildHeader();
            Header header = rebuildHeader.Rebuild(headerData);
            file.Header = header;

            byte[] windowData = new byte[] {
                // Window
                0x01,       // Win_Indicator
                0x3A,       // Source segment size
                0x00,       // Source segment position
                0x35,       // Length of the delta encoding 
                0x81, 0x0E, // Size of the target window
                0x00,       // Delta_Indicator (no compression)
                0x14,       // Length of data for ADDs and RUNs
                0x18,       // Length of instructions and sizes
                0x03,       // Length of addresses for COPYs
                // Data section for ADDs and RUNs :   \nnot \nIt was a lie !
                0x0A, 0x6E, 0x6F, 0x74, 0x20, 0x0A,
                0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x65, 0x20, 0x21,                
                // Instructions and sizes section
                0x03, 0x3A, 0x00,   // COPY | Size 58 | No mode
                0x02, 0x01, 0x00,   // RUN  | Size 01 | No mode
                0x03, 0x06, 0x00,   // COPY | Size 06 | No mode
                0x01, 0x04, 0x00,   // ADD  | Size 04 | No mode
                0x03, 0x34, 0x00,   // COPY | Size 52 | No mode
                0x02, 0x01, 0x00,   // RUN  | Size 01 | No mode
                0x01, 0x0D, 0x00,   // ADD  | Size 13 | No mode
                0x02, 0x05, 0x00,   // RUN  | Size 05 | No mode
                // Addresses section for COPYs
                0x00, 0x00, 0x06
            };
            RebuildWindows rebuildWindows = new RebuildWindows();
            IList<Window> windowsList = rebuildWindows.Rebuild(windowData);
            file.WindowsList = windowsList;

            string path = @"VCDFile_Writer.vcd";
            file.Write(path);

            byte[] expected = {
                // Header
                0xD6,   // V
                0xC3,   // C
                0xC4,   // D
                0x00,   // VCDIFF Version
                0x00,   // Hdr_Indicator : no custom code table, no compression
                0x00,   // Secondary compressor ID
                0x00,   // Length of code table data
                0x00,   // Size of near cache 
                0x00,   // Size of same cache
                // Window
                0x01,       // Win_Indicator
                0x3A,       // Source segment size
                0x00,       // Source segment position
                0x35,       // Length of the delta encoding 
                0x81, 0x0E, // Size of the target window
                0x00,       // Delta_Indicator (no compression)
                0x14,       // Length of data for ADDs and RUNs
                0x18,       // Length of instructions and sizes
                0x03,       // Length of addresses for COPYs
                // Data section for ADDs and RUNs :   \nnot \nIt was a lie !
                0x0A, 0x6E, 0x6F, 0x74, 0x20, 0x0A,
                0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x65, 0x20, 0x21,                
                // Instructions and sizes section
                0x03, 0x3A, 0x00,   // COPY | Size 58 | No mode
                0x02, 0x01, 0x00,   // RUN  | Size 01 | No mode
                0x03, 0x06, 0x00,   // COPY | Size 06 | No mode
                0x01, 0x04, 0x00,   // ADD  | Size 04 | No mode
                0x03, 0x34, 0x00,   // COPY | Size 52 | No mode
                0x02, 0x01, 0x00,   // RUN  | Size 01 | No mode
                0x01, 0x0D, 0x00,   // ADD  | Size 13 | No mode
                0x02, 0x05, 0x00,   // RUN  | Size 05 | No mode
                // Addresses section for COPYs
                0x00, 0x00, 0x06
            };

            byte[] actual = File.ReadAllBytes(path);
            
            bool same = true;

            if (expected.Length != actual.Length)
                same = false;
            else
                for (int i = 0; i < expected.Length; i++)
                    if (expected[i] != actual[i])
                        same = false;

            Assert.AreEqual(true, same);
        }

        /// <summary>
        ///A test for Read
        ///</summary>
        [TestMethod()]
        public void ReadTest()
        {
            byte[] data = {
                // Header
                0xD6,   // V
                0xC3,   // C
                0xC4,   // D
                0x00,   // VCDIFF Version
                0x00,   // Hdr_Indicator : no custom code table, no compression
                0x00,   // Secondary compressor ID
                0x00,   // Length of code table data
                0x00,   // Size of near cache 
                0x00,   // Size of same cache
                // Window
                0x01,       // Win_Indicator
                0x3A,       // Source segment size
                0x00,       // Source segment position
                0x35,       // Length of the delta encoding 
                0x81, 0x0E, // Size of the target window
                0x00,       // Delta_Indicator (no compression)
                0x14,       // Length of data for ADDs and RUNs
                0x18,       // Length of instructions and sizes
                0x03,       // Length of addresses for COPYs
                // Data section for ADDs and RUNs :   \nnot \nIt was a lie !
                0x0A, 0x6E, 0x6F, 0x74, 0x20, 0x0A,
                0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x65, 0x20, 0x21,                
                // Instructions and sizes section
                0x03, 0x3A, 0x00,   // COPY | Size 58 | No mode
                0x02, 0x01, 0x00,   // RUN  | Size 01 | No mode
                0x03, 0x06, 0x00,   // COPY | Size 06 | No mode
                0x01, 0x04, 0x00,   // ADD  | Size 04 | No mode
                0x03, 0x34, 0x00,   // COPY | Size 52 | No mode
                0x02, 0x01, 0x00,   // RUN  | Size 01 | No mode
                0x01, 0x0D, 0x00,   // ADD  | Size 13 | No mode
                0x02, 0x05, 0x00,   // RUN  | Size 05 | No mode
                // Addresses section for COPYs
                0x00, 0x00, 0x06
            };

            string path = @"VCDFile_Reader.vcd";
            File.WriteAllBytes(path, data);

            VCDFile file = new VCDFile();
            file.Read(path);


            Header expectedHeader = new Header();
            expectedHeader.Header1 = 0xD6;
            expectedHeader.Header2 = 0xC3;
            expectedHeader.Header3 = 0xC4;
            expectedHeader.Header4 = 0x00;
            expectedHeader.HdrIndicator = 0x00;
            expectedHeader.SecondaryCompressorId = 0x00;
            expectedHeader.CodeTableDataLength = 0x00;
            expectedHeader.NearCacheSize = 0x00;
            expectedHeader.SameCacheSize = 0x00;

            Header actualHeader = file.Header;
            bool same = true;

            if (expectedHeader.Header1 != actualHeader.Header1)
                same = false;
            if (expectedHeader.Header2 != actualHeader.Header2)
                same = false;
            if (expectedHeader.Header3 != actualHeader.Header3)
                same = false;
            if (expectedHeader.Header4 != actualHeader.Header4)
                same = false;
            if (expectedHeader.HdrIndicator != actualHeader.HdrIndicator)
                same = false;
            if (expectedHeader.SecondaryCompressorId != actualHeader.SecondaryCompressorId)
                same = false;
            if (expectedHeader.CodeTableDataLength != actualHeader.CodeTableDataLength)
                same = false;
            if (expectedHeader.NearCacheSize != actualHeader.NearCacheSize)
                same = false;
            if (expectedHeader.SameCacheSize != actualHeader.SameCacheSize)
                same = false;

            Window expectedW1 = new Window();
            expectedW1.WinIndicator = 0x01;
            expectedW1.SourceSegmentSize = 58;
            expectedW1.SourceSegmentPosition = 0;
            expectedW1.DeltaEncodingLength = 53;
            expectedW1.TargetWindowSize = 142;
            expectedW1.DeltaIndicator = 0x00;
            expectedW1.AddAndRunDataLength = 20;
            expectedW1.InstructionsAndSizesLength = 24;
            expectedW1.CopyAddressesLength = 3;
            expectedW1.AddAndRunDataSection = new byte[20] { 0x0A, 0x6E, 0x6F, 0x74, 0x20, 0x0A,
                0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x65, 0x20, 0x21 };
            expectedW1.InstructionsAndSizesSection = new byte[24] { 0x03, 0x3A, 0x00, 0x02, 0x01, 0x00,
                0x03, 0x06, 0x00, 0x01, 0x04, 0x00, 0x03, 0x34, 0x00, 0x02, 0x01, 0x00,
                0x01, 0x0D, 0x00, 0x02, 0x05, 0x00 };
            expectedW1.CopyAddressesSection = new byte[3] { 0x00, 0x00, 0x06 }; 

            IList<Window> expectedList = new List<Window>();
            expectedList.Add(expectedW1);

            IList<Window> actual = file.WindowsList;
            int index = 0;

            foreach (Window window in expectedList)
            {
                if (window.WinIndicator != actual[index].WinIndicator)
                    same = false;
                if (window.SourceSegmentSize != actual[index].SourceSegmentSize)
                    same = false;
                if (window.SourceSegmentPosition != actual[index].SourceSegmentPosition)
                    same = false;
                if (window.DeltaEncodingLength != actual[index].DeltaEncodingLength)
                    same = false;
                if (window.TargetWindowSize != actual[index].TargetWindowSize)
                    same = false;
                if (window.DeltaIndicator != actual[index].DeltaIndicator)
                    same = false;
                if (window.AddAndRunDataLength != actual[index].AddAndRunDataLength)
                    same = false;
                if (window.InstructionsAndSizesLength != actual[index].InstructionsAndSizesLength)
                    same = false;
                if (window.CopyAddressesLength != actual[index].CopyAddressesLength)
                    same = false;
                if (window.AddAndRunDataSection.Length != actual[index].AddAndRunDataSection.Length)
                    same = false;
                else
                    for (int i = 0; i < window.AddAndRunDataSection.Length; i++)
                        if (window.AddAndRunDataSection[i] != actual[index].AddAndRunDataSection[i])
                            same = false;
                if (window.InstructionsAndSizesSection.Length != actual[index].InstructionsAndSizesSection.Length)
                    same = false;
                else
                    for (int i = 0; i < window.InstructionsAndSizesSection.Length; i++)
                        if (window.InstructionsAndSizesSection[i] != actual[index].InstructionsAndSizesSection[i])
                            same = false;
                if (window.CopyAddressesSection.Length != actual[index].CopyAddressesSection.Length)
                    same = false;
                else
                    for (int i = 0; i < window.CopyAddressesSection.Length; i++)
                        if (window.CopyAddressesSection[i] != actual[index].CopyAddressesSection[i])
                            same = false;
                index++;
            }

            Assert.AreEqual(true, same);
        }

        /// <summary>
        ///A test for VCDFile Constructor
        ///</summary>
        [TestMethod()]
        public void VCDFileConstructorTest()
        {
            VCDFile target = new VCDFile();
        }
    }
}
